#include <iostream>
#include <functional>
#include <memory>
#include "TcpServer.hpp"
#include "Protocol.hpp"
#include "Calculate.hpp"

using namespace protocol_ns;

void Usage(std::string proc)
{
  std::cout << "Usage:\n\t" << proc << " local_port\n"
            << std::endl;
}

using callback_t = std::function<Response(const Request &req)>;

class Service
{
public:
  Service(callback_t cb) : _cb(cb)
  {
  }
  void ServiceHelper(socket_sptr sockptr, InetAddr client)
  {
    int sockfd = sockptr->SockFd();
    LOG(DEBUG, "get a new link ,info %s:%d,fd:%d", client.Ip(), client.Port(), sockfd);
    std::string clientaddr = "[" + client.Ip() + ":" + std::to_string(client.Port()) + "] ";
    std::string inbuffer;
    while (true)
    {
      sleep(5); // 测试用，人为的让服务端先不处理，积压一部分请求，测试服务器是否能够解决TCP粘包问题
      Request req;
      // 1.读取数据
      int n = sockptr->Recv(&inbuffer); // 如何保证读到的是一个完整的请求？
      if (n < 0)
      {
        LOG(DEBUG, "client %s quit", clientaddr.c_str());
        break;
      }
      // 2.分析数据，获取完整报文
      std::string package;
      while (true)
      {
        sleep(1);
        std::cout << "服务器未处理的请求: " << inbuffer << std::endl;
        package = Decode(inbuffer);
        if (package.empty())
          break; // 证明此时没有一个完整的报文继续读取，这也是为什么Socket类中Recv接口中*out+=inbuffer;是+=的原因
        // 代码执行到这一定有完整json字符串
        std::cout << "----------------------begin----------------------" << std::endl;
        std::cout << "请求json字符串:\n"
                  << package << std::endl;
        // 3.反序列化
        req.Deserialize(package);
        // 4.业务处理
        Response resp = _cb(req);
        // 5.对响应序列化
        std::string send_str;
        resp.Serialize(&send_str);

        std::cout << "响应序列化:" << std::endl;
        std::cout << send_str << std::endl;

        // 6.添加长度报头
        send_str = Encode(send_str);
        std::cout << "响应完整报文:" << std::endl;
        std::cout << send_str << std::endl;
        sockptr->Send(send_str); // 本次不对发送做处理 EPOLL
      }
    }
  }

private:
  callback_t _cb;
};

// ./tcpserver port
// 云服务器的port默认都是禁止访问的。云服务器放开端口8080 ~ 8085
int main(int argc, char *argv[])
{
  if (argc != 2)
  {
    Usage(argv[0]);
    // exit(USAGE_ERROR);
    return 1;
  }
  uint16_t port = std::stoi(argv[1]);
  Calculate cal;                                                                  // 应用层
  Service calservice(std::bind(&Calculate::Excute, &cal, std::placeholders::_1)); // 表示层
  io_service_t service = std::bind(&Service::ServiceHelper, &calservice, std::placeholders::_1, std::placeholders::_2);
  std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(port, service); // 会话层
  tsvr->Loop();
  return 0;
}
